package com.example.micro_property_springboot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.micro_property_springboot.mapper.AssetCheckDiffMapper;
import com.example.micro_property_springboot.mapper.AssetCheckItemMapper;
import com.example.micro_property_springboot.mapper.AssetInfoMapper;
import com.example.micro_property_springboot.pojo.AssetCheckDiff;
import com.example.micro_property_springboot.pojo.AssetCheckItem;
import com.example.micro_property_springboot.pojo.AssetInfo;
import com.example.micro_property_springboot.pojo.DTO.request.AssetCheckDiffHandleRequest;
import com.example.micro_property_springboot.service.AssetCheckDiffService;
import com.example.micro_property_springboot.service.AssetInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
 * 资产盘点差异服务实现类
 */
@Slf4j
@Service
public class AssetCheckDiffServiceImpl extends ServiceImpl<AssetCheckDiffMapper, AssetCheckDiff> implements AssetCheckDiffService {

    @Autowired
    private AssetCheckDiffMapper assetCheckDiffMapper;

    @Autowired
    private AssetCheckItemMapper assetCheckItemMapper;

    @Autowired
    private AssetInfoMapper assetInfoMapper;

    @Autowired
    private AssetInfoService assetInfoService;


    /**
     * 根据盘点计划获取应盘点的资产列表
     */
    private List<AssetInfo> getExpectedAssetsByPlan(Long planId) {
        // TODO: 根据盘点计划的check_scope和scope_id查询应盘点的资产
        // 这里需要实现具体的业务逻辑，根据盘点范围查询资产
        QueryWrapper<AssetInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", "正常"); // 只盘点正常状态的资产
        return assetInfoMapper.selectList(queryWrapper);
    }

    /**
     * 获取实际已盘点的资产列表
     */
    private List<AssetCheckItem> getActualCheckedAssets(Long planId) {
        QueryWrapper<AssetCheckItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("plan_id", planId);
        queryWrapper.eq("check_status", "CHECKED"); // 只获取已盘点的记录
        return assetCheckItemMapper.selectList(queryWrapper);
    }

    /**
     * 生成盘亏差异（应盘点但未盘点的资产）
     */
    private void generateLossDiffs(Long planId, List<AssetInfo> expectedAssets, List<AssetCheckItem> actualCheckedItems) {
        // 获取实际已盘点的资产ID集合
        List<Long> actualAssetIds = actualCheckedItems.stream()
                .map(AssetCheckItem::getAssetId)
                .collect(Collectors.toList());

        // 找出应盘点但未盘点的资产（盘亏）
        List<AssetInfo> lossAssets = expectedAssets.stream()
                .filter(asset -> !actualAssetIds.contains(asset.getId()))
                .collect(Collectors.toList());

        log.info("发现盘亏资产数量: {}", lossAssets.size());

        // 生成盘亏差异记录
        List<AssetCheckDiff> lossDiffs = new ArrayList<>();
        for (AssetInfo asset : lossAssets) {
            AssetCheckDiff diff = new AssetCheckDiff();
            diff.setPlanId(planId);
            diff.setAssetId(asset.getId());
            diff.setDiffType("LOSS");
            diff.setReason("资产在盘点范围内但未找到实物");
            diff.setHandlerId(null); // 待处理
            diff.setHandleTime(null); // 待处理
            diff.setCreateTime(LocalDateTime.now());
            lossDiffs.add(diff);
        }

        if (!lossDiffs.isEmpty()) {
            saveBatch(lossDiffs);
            log.info("保存盘亏差异记录数量: {}", lossDiffs.size());
        }
    }

    /**
     * 生成盘盈差异（未在应盘点列表中但实际盘点的资产）
     */
    private void generateProfitDiffs(Long planId, List<AssetInfo> expectedAssets, List<AssetCheckItem> actualCheckedItems) {
        // 获取应盘点的资产ID集合
        List<Long> expectedAssetIds = expectedAssets.stream()
                .map(AssetInfo::getId)
                .collect(Collectors.toList());

        // 找出未在应盘点列表中但实际盘点的资产（盘盈）
        List<AssetCheckItem> profitItems = actualCheckedItems.stream()
                .filter(item -> !expectedAssetIds.contains(item.getAssetId()))
                .collect(Collectors.toList());

        log.info("发现盘盈资产数量: {}", profitItems.size());

        // 生成盘盈差异记录
        List<AssetCheckDiff> profitDiffs = new ArrayList<>();
        for (AssetCheckItem item : profitItems) {
            AssetCheckDiff diff = new AssetCheckDiff();
            diff.setPlanId(planId);
            diff.setAssetId(item.getAssetId());
            diff.setDiffType("PROFIT");
            diff.setReason("发现不在盘点范围内的资产");
            diff.setHandlerId(null); // 待处理
            diff.setHandleTime(null); // 待处理
            diff.setCreateTime(LocalDateTime.now());
            profitDiffs.add(diff);
        }

        if (!profitDiffs.isEmpty()) {
            saveBatch(profitDiffs);
            log.info("保存盘盈差异记录数量: {}", profitDiffs.size());
        }
    }
    /**
     * 生成盘点差异
     * @param planId 盘点计划ID
     */
    @Override
    public void generateCheckDiffs(Long planId) {
        log.info("开始生成盘点计划ID为{}的差异数据", planId);

        // 1. 获取盘点计划中应该盘点的资产列表（根据盘点范围）
        QueryWrapper<AssetInfo> expectedQuery = new QueryWrapper<>();
        expectedQuery.eq("status", "正常"); // 只盘点正常状态的资产
        List<AssetInfo> expectedAssets = assetInfoMapper.selectList(expectedQuery);
        log.info("盘点计划应盘点资产数量: {}", expectedAssets.size());

        // 2. 获取实际已盘点的资产列表
        QueryWrapper<AssetCheckItem> actualQuery = new QueryWrapper<>();
        actualQuery.eq("plan_id", planId);
        actualQuery.eq("check_status", "CHECKED");
        List<AssetCheckItem> actualCheckedItems = assetCheckItemMapper.selectList(actualQuery);
        log.info("实际已盘点资产数量: {}", actualCheckedItems.size());

        // 3. 对比生成盘亏差异（应盘点但未盘点的资产）
        generateLossDiffs(planId, expectedAssets, actualCheckedItems);

        // 4. 对比生成盘盈差异（未在应盘点列表中但实际盘点的资产）
        generateProfitDiffs(planId, expectedAssets, actualCheckedItems);

        log.info("盘点差异生成完成，计划ID: {}", planId);
    }

    @Override
    public List<AssetCheckDiff> getAssetCheckDiffs(Long planId, String diffType) {
        QueryWrapper<AssetCheckDiff> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("plan_id", planId);

        if (diffType != null && !diffType.isEmpty()) {
            queryWrapper.eq("diff_type", diffType);
        }

        queryWrapper.orderByDesc("create_time");
        return list(queryWrapper);
    }

    @Override
    @Transactional
    public AssetCheckDiff handleAssetCheckDiff(Long diffId, AssetCheckDiffHandleRequest request, Long userId) {
        log.info("处理盘点差异，差异ID: {}, 处理人ID: {}", diffId, userId);

        AssetCheckDiff diff = getById(diffId);
        if (diff == null) {
            throw new RuntimeException("盘点差异不存在");
        }

        if (diff.getHandlerId() != null) {
            throw new RuntimeException("该盘点差异已被处理，无法重复处理");
        }

        // 更新差异处理信息
        diff.setReason(request.getReason());
        diff.setHandlerId(userId);
        diff.setHandleTime(LocalDateTime.now());
        diff.setCreateTime(LocalDateTime.now());

        // 根据差异类型进行不同的业务处理
        if ("PROFIT".equals(diff.getDiffType())) {
            handleProfitDiff(diff, request);
        } else if ("LOSS".equals(diff.getDiffType())) {
            handleLossDiff(diff, request);
        }

        saveOrUpdate(diff);
        log.info("盘点差异处理完成，差异ID: {}", diffId);

        return diff;
    }

    /**
     * 处理盘盈差异
     */
    private void handleProfitDiff(AssetCheckDiff diff, AssetCheckDiffHandleRequest request) {
        // 盘盈处理：确认资产信息并更新状态
        AssetInfo assetInfo = assetInfoService.getById(diff.getAssetId());
        if (assetInfo != null) {
            // 如果资产已存在，更新状态为正常
            assetInfo.setStatus("正常");
            assetInfo.setUpdateTime(LocalDateTime.now());
            assetInfoService.saveOrUpdate(assetInfo);
            log.info("盘盈资产状态已更新，资产ID: {}", diff.getAssetId());
        } else {
            // 如果资产不存在，需要创建新资产（需要前端提供完整的资产信息）
            if (request.getAssetInfo() != null) {
                AssetInfo newAsset = request.getAssetInfo();
                newAsset.setId(diff.getAssetId());
                newAsset.setCreateTime(LocalDateTime.now());
                newAsset.setUpdateTime(LocalDateTime.now());
                assetInfoService.save(newAsset);
                log.info("创建新盘盈资产，资产ID: {}", diff.getAssetId());
            }
        }
    }

    /**
     * 处理盘亏差异
     */
    private void handleLossDiff(AssetCheckDiff diff, AssetCheckDiffHandleRequest request) {
        // 盘亏处理：更新资产状态为丢失或报废
        AssetInfo assetInfo = assetInfoService.getById(diff.getAssetId());
        if (assetInfo != null) {
            String newStatus = determineAssetStatus(request.getReason());
            assetInfo.setStatus(newStatus);
            assetInfo.setUpdateTime(LocalDateTime.now());
            assetInfoService.saveOrUpdate(assetInfo);
            log.info("盘亏资产状态已更新为{}，资产ID: {}", newStatus, diff.getAssetId());
        }
    }

    /**
     * 根据处理原因确定资产状态
     */
    private String determineAssetStatus(String reason) {
        if (reason.contains("报废") || reason.contains("损坏")) {
            return "报废";
        } else if (reason.contains("丢失") || reason.contains("遗失")) {
            return "丢失";
        } else {
            return "盘亏";
        }
    }

    @Override
    @Transactional
    public void confirmAssetCheckDiffs(Long planId, Long userId) {
        log.info("确认盘点差异，计划ID: {}, 确认人ID: {}", planId, userId);

        // 检查是否存在未处理的盘点差异
        QueryWrapper<AssetCheckDiff> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("plan_id", planId);
        queryWrapper.isNull("handler_id");

        List<AssetCheckDiff> unhandledDiffs = list(queryWrapper);
        if (!unhandledDiffs.isEmpty()) {
            throw new RuntimeException("存在" + unhandledDiffs.size() + "条未处理的盘点差异，请先处理后再确认");
        }

        // 获取所有已处理的差异
        QueryWrapper<AssetCheckDiff> handledQuery = new QueryWrapper<>();
        handledQuery.eq("plan_id", planId);
        handledQuery.isNotNull("handler_id");
        List<AssetCheckDiff> handledDiffs = list(handledQuery);

        if (handledDiffs.isEmpty()) {
            log.info("盘点计划ID: {} 无差异需要确认", planId);
            return;
        }

        // 执行确认后的业务逻辑
        performPostConfirmationActions(planId, handledDiffs, userId);

        log.info("盘点差异确认完成，计划ID: {}", planId);
    }

    /**
     * 执行确认后的业务逻辑
     */
    private void performPostConfirmationActions(Long planId, List<AssetCheckDiff> handledDiffs, Long userId) {
        // 1. 更新盘点计划状态为已完成（需要调用盘点计划服务）
        // assetCheckPlanService.completeAssetCheckPlan(planId);

        // 2. 生成盘点报告（可以记录到日志或生成文件）
        generateCheckReport(planId, handledDiffs);

        // 3. 发送通知（可选）
        sendConfirmationNotification(planId, handledDiffs.size(), userId);
    }

    /**
     * 生成盘点报告
     */
    private void generateCheckReport(Long planId, List<AssetCheckDiff> handledDiffs) {
        long profitCount = handledDiffs.stream()
                .filter(diff -> "PROFIT".equals(diff.getDiffType()))
                .count();
        long lossCount = handledDiffs.stream()
                .filter(diff -> "LOSS".equals(diff.getDiffType()))
                .count();

        log.info("盘点报告 - 计划ID: {}", planId);
        log.info("盘盈数量: {}", profitCount);
        log.info("盘亏数量: {}", lossCount);
        log.info("总差异数量: {}", handledDiffs.size());
    }

    /**
     * 发送确认通知
     */
    private void sendConfirmationNotification(Long planId, int diffCount, Long userId) {
        // TODO: 实现通知逻辑，可以发送邮件、消息等
        log.info("发送盘点差异确认通知 - 计划ID: {}, 差异数量: {}, 确认人ID: {}",
                planId, diffCount, userId);
    }
}